package com.hp.bon.sgw.wh.channel;

import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import prov.inter.ProvinceWsInterDelegate;
import prov.inter.ProvinceWsInterService;

import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.Constants.NodeStatus;
import com.hp.bon.sgw.Constants.ResultCode;
import com.hp.bon.sgw.bean.XmlMessage;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.core.InprogressMessageQueue;
import com.hp.bon.sgw.core.channel.IChannel;
import com.hp.bon.sgw.domain.SGWChannel;
import com.hp.bon.sgw.service.ConfigListener;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;
import com.hp.ocs.diameter.message.AVP;
import com.hp.ocs.diameter.message.AVP_Grouped;
import com.hp.ocs.diameter.message.AVP_UTF8String;
import com.hp.ocs.diameter.message.AVP_Unsigned64;
import com.hp.ocs.diameter.message.InvalidAVPLengthException;
import com.hp.ocs.diameter.message.Message;

//安徽永不停机
public class ProvinceChannel implements ConfigListener, IChannel {

	private static final Logger logger = LoggerFactory
			.getLogger(ProvinceChannel.class);
	private SGWChannel channel;
	protected ConfigService confSrv;

	public ProvinceChannel(SGWChannel channel) {
		this.channel = channel;
		confSrv = SpringContext.getInstance().getConfigService();
	}

	@Override
	public void addPersist(com.hp.bon.sgw.domain.Node arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void deletePersist(com.hp.bon.sgw.domain.Node arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public Set<String> monitorConfKeys() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onConfigUpdated(String updatedKey) {
		// TODO Auto-generated method stub

	}

	@Override
	public SGWChannel getSGWChannel() {
		return this.channel;
	}

	@Override
	public int getThreadPoolSize() {
		return executor.getPoolSize();
	}

	@Override
	public int getThreadPoolQueueSize() {
		return executor.getQueue().size();
	}

	@Override
	public int getThreadPoolActiveCount() {
		return executor.getActiveCount();
	}

	@Override
	public int getNodeSendQueueSize(String nodeHostId) {
		// TODO Auto-generated method stub
		return 0;
	}

	ThreadPoolExecutor executor;
	ThreadPoolExecutor collector;

	@Override
	public void start() throws IOException {
		logger.info("start ProvinceChannel ...");
		this.channel.setStatus(NodeStatus.ON_LINE);
		confSrv.updateChannelStatus2DB(this.channel.getId(), NodeStatus.ON_LINE);
	}

	@Override
	public void stop() {
		logger.info("stop ProvinceChannel ...");
		this.channel.setStatus(NodeStatus.OFF_LINE);
		confSrv.updateChannelStatus2DB(this.channel.getId(),
				NodeStatus.OFF_LINE);
	}

	@Override
	public int sendRequest(CallParam callParam) {
		if (logger.isDebugEnabled()) {
			logger.debug(callParam.getSessionId()
					+ ", prepare forward request to WingPay:"
					+ callParam.getToNode().getServerUrl());
		}
		Message request = (Message) callParam.getRequest();
		AVP avp = null;
		try {
			avp = request.find(Constants.DIAMETER_AVP_SERVICE_INFOMATION,
					Constants.DIAMETER_VENDOR_3GPP);
			if (avp != null) {
				AVP_Grouped serviceInformationAVP = new AVP_Grouped(avp);
				// 产品标识
				AVP productLogoAVP = serviceInformationAVP.find(80201,
						Constants.DIAMETER_VENDOR_CT);
				String productLogo = new AVP_UTF8String(productLogoAVP)
						.queryValue();
				// 产品号类型
				AVP productTypeAVP = serviceInformationAVP.find(80202,
						Constants.DIAMETER_VENDOR_CT);
				String productType = new AVP_UTF8String(productTypeAVP)
						.queryValue();
				// 电信产品号
				AVP productNoAVP = serviceInformationAVP.find(80203,
						Constants.DIAMETER_VENDOR_CT);
				String productNo = new AVP_UTF8String(productNoAVP)
						.queryValue();
				// 外部业务类型
				AVP businessTypeAVP = serviceInformationAVP.find(80204,
						Constants.DIAMETER_VENDOR_CT);
				String businessType = new AVP_UTF8String(businessTypeAVP)
						.queryValue();
				// 交易代码
				AVP txnTypeAVP = serviceInformationAVP.find(80205,
						Constants.DIAMETER_VENDOR_CT);
				String txnType = new AVP_UTF8String(txnTypeAVP).queryValue();
				// 交易金额
				AVP txnaMountAVP = serviceInformationAVP.find(80206,
						Constants.DIAMETER_VENDOR_CT);
				long txnaMount = new AVP_Unsigned64(txnaMountAVP).queryValue();
				// 支付机构
				AVP payOrgCodeAVP = serviceInformationAVP.find(80207,
						Constants.DIAMETER_VENDOR_CT);
				String payOrgCode = new AVP_UTF8String(payOrgCodeAVP)
						.queryValue();
				// 出单机构
				AVP supplyOrgCodeAVP = serviceInformationAVP.find(80208,
						Constants.DIAMETER_VENDOR_CT);
				String supplyOrgCode = new AVP_UTF8String(supplyOrgCodeAVP)
						.queryValue();
				// 受理机构
				AVP acceptOrgCodeAVP = serviceInformationAVP.find(80209,
						Constants.DIAMETER_VENDOR_CT);
				String acceptOrgCode = new AVP_UTF8String(acceptOrgCodeAVP)
						.queryValue();
				// 受理人
				AVP acceptUidAVP = serviceInformationAVP.find(80210,
						Constants.DIAMETER_VENDOR_CT);
				String acceptUid = new AVP_UTF8String(acceptUidAVP)
						.queryValue();
				// 受理地区代码
				AVP acceptAreaCodeAVP = serviceInformationAVP.find(80211,
						Constants.DIAMETER_VENDOR_CT);
				long acceptAreaCode = new AVP_Unsigned64(acceptAreaCodeAVP)
						.queryValue();
				// 受理城市代码
				AVP acceptCityCodeAVP = serviceInformationAVP.find(80212,
						Constants.DIAMETER_VENDOR_CT);
				long acceptCityCode = new AVP_Unsigned64(acceptCityCodeAVP)
						.queryValue();
				// 受理渠道
				AVP acceptChannelAVP = serviceInformationAVP.find(80213,
						Constants.DIAMETER_VENDOR_CT);
				String acceptChannel = new AVP_UTF8String(acceptChannelAVP)
						.queryValue();
				// 受理流水
				AVP acceptSeqNoAVP = serviceInformationAVP.find(80214,
						Constants.DIAMETER_VENDOR_CT);
				String acceptSeqNo = new AVP_UTF8String(acceptSeqNoAVP)
						.queryValue();
				// 受理时间
				AVP acceptTransTimeAVP = serviceInformationAVP.find(80215,
						Constants.DIAMETER_VENDOR_CT);
				String acceptTransTime = new AVP_UTF8String(acceptTransTimeAVP)
						.queryValue();
				// 商户流水号
				AVP supplySeqNoAVP = serviceInformationAVP.find(80216,
						Constants.DIAMETER_VENDOR_CT);
				long supplySeqNo = new AVP_Unsigned64(supplySeqNoAVP)
						.queryValue();

				String sendMSG = null;

				// 拼接soap消息
				StringBuilder builder = new StringBuilder();
				builder.append("<PayPlatRequestParameter>")
						.append("<CTRL-INFO WEBSVRNAME=" + "\"翼支付账户（升级版）代扣\" "
								+ "WEBSVRCODE=" + "\"600605\" " + "APPFROM="
								+ "\"420000-INAS\" " + "KEEP="
								+ "\"07201305291348389691\" " + "/>")
						.append("<PARAMETERS>");
				// productLogo
				if (productLogo != null) {
					builder.append("<PRODUCTLOGO>" + productLogo
							+ "</PRODUCTLOGO>");
				} else {
					builder.append("<PRODUCTLOGO></PRODUCTLOGO>");
				}
				// productType
				if (productType != null) {
					builder.append("<PRODUCTTYPE>" + productType
							+ "</PRODUCTTYPE>");
				} else {
					builder.append("<PRODUCTTYPE></PRODUCTTYPE>");
				}
				// PRODUCTNO
				if (productNo != null) {
					builder.append("<PRODUCTNO>" + productNo + "</PRODUCTNO>");
				} else {
					builder.append("<PRODUCTNO></PRODUCTNO>");
				}
				// BUSINESSTYPE
				if (businessType != null) {
					builder.append("<BUSINESSTYPE>" + businessType
							+ "</BUSINESSTYPE>");
				} else {
					builder.append("<BUSINESSTYPE></BUSINESSTYPE>");
				}
				// TXNTYPE
				if (txnType != null) {
					builder.append("<TXNTYPE>" + txnType + "</TXNTYPE>");
				} else {
					builder.append("<TXNTYPE></TXNTYPE>");
				}
				// TXNAMOUNT 如果是long类型的为空是为0么？
				if (txnaMount != 0) {
					builder.append("<TXNAMOUNT>" + txnaMount + "</TXNAMOUNT>");
				} else {
					builder.append("<TXNAMOUNT></TXNAMOUNT>");
				}
				// PAYORGCODE
				if (payOrgCode != null) {
					builder.append("<PAYORGCODE>" + payOrgCode
							+ "</PAYORGCODE>");
				} else {
					builder.append("<PAYORGCODE></PAYORGCODE>");
				}
				// SUPPLYORGCODE
				if (supplyOrgCode != null) {
					builder.append("<SUPPLYORGCODE>" + supplyOrgCode
							+ "</SUPPLYORGCODE>");
				} else {
					builder.append("<SUPPLYORGCODE></SUPPLYORGCODE>");
				}
				// ACCEPTORGCODE
				if (supplyOrgCode != null) {
					builder.append("<ACCEPTORGCODE>" + acceptOrgCode
							+ "</ACCEPTORGCODE>");
				} else {
					builder.append("<ACCEPTORGCODE></ACCEPTORGCODE>");
				}
				// ACCEPTUID
				if (acceptUid != null) {
					builder.append("<ACCEPTUID>" + acceptUid + "</ACCEPTUID>");
				} else {
					builder.append("<ACCEPTUID></ACCEPTUID>");
				}
				// ACCEPTAREACODE 如果是long类型的为空是为0么？
				if (acceptAreaCode != 0) {
					builder.append("<ACCEPTAREACODE>" + acceptAreaCode
							+ "</ACCEPTAREACODE>");
				} else {
					builder.append("<ACCEPTAREACODE></ACCEPTAREACODE>");
				}
				// ACCEPTCITYCODE 如果是long类型的为空是为0么？
				if (acceptCityCode != 0) {
					builder.append("<ACCEPTCITYCODE>" + acceptCityCode
							+ "</ACCEPTCITYCODE>");
				} else {
					builder.append("<ACCEPTCITYCODE></ACCEPTCITYCODE>");
				}
				// ACCEPTCHANNEL
				if (acceptChannel != null) {
					builder.append("<ACCEPTCHANNEL>" + acceptChannel
							+ "</ACCEPTCHANNEL>");
				} else {
					builder.append("<ACCEPTCHANNEL></ACCEPTCHANNEL>");
				}
				// ACCEPTSEQNO
				if (acceptSeqNo != null) {
					builder.append("<ACCEPTSEQNO>" + acceptSeqNo
							+ "</ACCEPTSEQNO>");
				} else {
					builder.append("<ACCEPTSEQNO></ACCEPTSEQNO>");
				}
				// ACCEPTTRANSTIME
				if (acceptTransTime != null) {
					builder.append("<ACCEPTTRANSTIME>" + acceptTransTime
							+ "</ACCEPTTRANSTIME>");
				} else {
					builder.append("<ACCEPTTRANSTIME></ACCEPTTRANSTIME>");
				}
				// SUPPLYSEQNO
				if (supplySeqNo != 0) {
					builder.append("<SUPPLYSEQNO>" + supplySeqNo
							+ "</SUPPLYSEQNO>");
				} else {
					builder.append("<SUPPLYSEQNO></SUPPLYSEQNO>");
				}
				builder.append("</PARAMETERS>").append(
						"</PayPlatRequestParameter>");

				sendMSG = builder.toString();
				// 发送拼接好的soap报文
				logger.info(callParam.getSessionId() + ", request: " + sendMSG);

				ProvinceWsInterDelegate pro = getProvinceWsInterClient(callParam
						.getToNode().getServerUrl());
				// 发送soap消息，response为收到的响应
				String response = pro.doBusiness(sendMSG);
				logger.info(callParam.getSessionId() + ", response:" + response);
				if (response != null) {
					// 将响应的response转化为xml，将字段取出封装成CCA发送
					Document doc = null;
					String responseCode = null;
					String responseDesc = null;
					String currDate = null;
					String balance = null;
					String originalTxnMount = null;
					String actualTxnMount = null;
					try {
						doc = DocumentHelper.parseText(response);
						Element root = doc.getRootElement();

						Node node = root
								.selectSingleNode("//PayPlatResponseParameter/RESPONSECODE");
						if (node != null) {
							responseCode = node.getStringValue();
						}

						node = root
								.selectSingleNode("//PayPlatResponseParameter/RESPONSECONTENT");
						if (node != null) {
							responseDesc = node.getStringValue();
						}

						node = root
								.selectSingleNode("//PayPlatResponseParameter/CURRDATE");
						if (node != null) {
							currDate = node.getStringValue();
						}

						node = root
								.selectSingleNode("//PayPlatResponseParameter/BALANCE");
						if (node != null) {
							balance = node.getStringValue();
						}

						node = root
								.selectSingleNode("//PayPlatResponseParameter/ORIGINALTXNMOUNT");
						if (node != null) {
							originalTxnMount = node.getStringValue();
						}

						node = root
								.selectSingleNode("//PayPlatResponseParameter/ACTUALTXNMOUNT");
						if (node != null) {
							actualTxnMount = node.getStringValue();
						}

						if(logger.isDebugEnabled()){
							logger.debug(callParam.getSessionId()
									+ ": responseCode=" + responseCode
									+ ", responseDesc=" + responseDesc
									+ ", currDate=" + currDate + ", balance="
									+ balance + ", originalTxnMount="
									+ originalTxnMount + ", actualTxnMount="
									+ actualTxnMount);
						}
						

						// 封装响应的的response发送CCA
						Element serviceInformation = DocumentHelper
								.createElement("Service_Information");
						Element element = null;
						if (responseCode != null) {
							element = serviceInformation
									.addElement("RESPONSECODE");
							element.setText(responseCode);
						}
						if (responseDesc != null) {
							element = serviceInformation
									.addElement("RESPONSEDESC");
							element.setText(responseDesc);
						}
						if (currDate != null) {
							element = serviceInformation.addElement("CURRDATE");
							element.setText(currDate);
						}
						if (balance != null) {
							element = serviceInformation.addElement("BALANCE");
							element.setText(balance);
						}
						if (originalTxnMount != null) {
							element = serviceInformation
									.addElement("ORIGINALTXNMOUNT");
							element.setText(originalTxnMount);
						}
						if (actualTxnMount != null) {
							element = serviceInformation
									.addElement("ACTUALTXNMOUNT");
							element.setText(actualTxnMount);
						}

						logger.info(callParam.getSessionId()
								+ ", WingPay response to XML:"
								+ serviceInformation.asXML());

						XmlMessage ack = new XmlMessage(false);
						ack.setMsgTime(System.currentTimeMillis());
						ack.setMID(callParam.getSessionId());
						ack.setSIG(null);
						ack.setRC("0");
						ack.setDS("");
						ack.setRTT("");
						ack.setREPTAG(0);
						ack.setLength(serviceInformation.asXML().length());
						ack.setDATA(serviceInformation.asXML());
						ack.setDataElement(serviceInformation);

						callParam.setRecvResponse(ack);

					} catch (Exception e) {
						e.printStackTrace();
						logger.warn(callParam.getSessionId()
								+ ",convert WingPay response error.");
						callParam.setRetCode(ResultCode.VALUE_ERROR);
						callParam.setResultMsg("convert WingPay response error"
								+ e.getLocalizedMessage());
					}
				}

			}
		} catch (InvalidAVPLengthException e) {
			e.printStackTrace();
			logger.warn(callParam.getSessionId() + ",convert DCC to XML error.");
			callParam.setRetCode(ResultCode.VALUE_ERROR);
			callParam.setResultMsg("convert DCC to XML error:"
					+ e.getLocalizedMessage());
		}

		CallParam _callParam = InprogressMessageQueue.getInstance()
				.removeProgress(callParam.getMessageUniqueID());
		if (logger.isDebugEnabled()) {
			logger.debug("remove progress form queue:"
					+ callParam.getMessageUniqueID());
		}
		if (_callParam == null) {
			logger.warn("msg queue not find callParam for "
					+ callParam.getMessageUniqueID());
		}

		callParam.getAsynHandler().onCallResult(callParam);
		return 0;
	}

	private static ProvinceWsInterDelegate getProvinceWsInterClient(
			String serverURL) {
		URL wsdlURL;
		QName serviceQname = new QName("http://wsi.huateng.com/","ProvinceWsInterService");
		String wsdl = "ProvinceWsInterPort.wsdl";
		try {
			wsdlURL = Thread.currentThread().getContextClassLoader().getResource(wsdl);
			if (wsdlURL == null) {
				throw new RuntimeException("cant' find wsdl file " + wsdl);
			}
		} catch (Exception e) {
			throw new RuntimeException("bad wsdl url:" + e);
		}
		ProvinceWsInterService serviceClient = new ProvinceWsInterService(wsdlURL, serviceQname);
		ProvinceWsInterDelegate client = serviceClient.getProvinceWsInterPort();
		Map<String, Object> ctx = ((BindingProvider) client).getRequestContext();
		ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serverURL);
		// ctx.put(BindingProviderProperties.REQUEST_TIMEOUT, 30000);
		// ctx.put(BindingProviderProperties.CONNECT_TIMEOUT, 10000);
		return client;
	}

}